package com.wtwd.device.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.wtwd.device.config.CacheConfig;
import com.wtwd.device.dao.WeatherMapper;
import com.wtwd.device.model.CityData;
import com.wtwd.device.model.GFWeather;
import com.wtwd.device.model.HeWeather;
import com.wtwd.device.model.entity.CityInfo;
import com.wtwd.device.model.entity.Weather;
import com.wtwd.device.model.vo.WeatherVO;
import com.wtwd.device.service.CacheService;
import com.wtwd.device.service.WeatherService;
import com.wtwd.device.util.DateUtils;
import com.wtwd.device.util.GFWeatherUtil;
import com.wtwd.device.util.WeatherUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zdl
 * @since 2021-08-10
 */
@Service
public class WeatherServiceImpl implements WeatherService {

    @Resource
    private WeatherMapper weatherMapper;

    @Resource
    private CacheService cacheService;

    public final static long THREE_HOUR = 8 * 60 * 60 * 1000;

    private static final Logger log = LoggerFactory.getLogger(WeatherServiceImpl.class);

    @Resource
    private GFWeatherUtil gfWeatherUtil;

    /**
     * 1.通过CID,获取缓存的天气数据,如果有判断时效THREE_HOUR,如果没有获取最新天气数据,并缓存新数据
     *
     * @param city
     * @param cid
     * @param lon
     * @param lat
     * @param lang
     * @param province
     * @param country
     * @return
     */
    @Override
    public WeatherVO getWeather(String city, String cid, String lon, String lat, String lang, String province, String country) {
        if (StringUtils.isAnyBlank(lon, lat, lang)) {//经纬度,和lang是必要参数
            return null;
        }
        if (!"cn".equals(lang)) {
            lang = "en";
        }
        if (StringUtils.isBlank(cid)) {
            //通过国家,省,市 缓存查询
            if (StringUtils.isNotBlank(city)) {
                cid = weatherMapper.getCidByCity(lang, city, province, country);
                if (StringUtils.isNotBlank(cid)) {//去掉城市id前缀
                    cid = cid.replaceAll("[^(0-9)]", "");
                }
            }
            if (StringUtils.isEmpty(cid)) {
                CityData cityData = WeatherUtil.getCityData(lon, lat, lang);
                if (cityData == null || CollectionUtils.isEmpty(cityData.getHeWeather6())) {
                    return null;
                }
                CityData.HeWeather6Bean heWeather6Bean = cityData.getHeWeather6().get(0);
                if (!"ok".equals(heWeather6Bean.getStatus())) {
                    return null;
                } else {
                    //保存城市信息
                    CityData.HeWeather6Bean.BasicBean basicBean = heWeather6Bean.getBasic().get(0);
                    cid = basicBean.getCid();
                    city = basicBean.getLocation();
                    country = basicBean.getCnty();
                    province = basicBean.getParent_city();
                    CityInfo cityInfo = new CityInfo();
                    cityInfo.setCid(cid);
                    if ("cn".equals(lang)) {
                        cityInfo.setCityCn(city);
                        cityInfo.setProvinceCn(province);
                        cityInfo.setCountryCn(country);
                    } else {
                        cityInfo.setCityEn(city);
                        cityInfo.setProvinceEn(province);
                        cityInfo.setCountryEn(country);
                    }
                    weatherMapper.replaceCityData(cityInfo);
                }
            }
        }
        Weather oldWeather = new LambdaQueryChainWrapper<>(weatherMapper)
                .eq(Weather::getCid, cid)
                .eq(Weather::getLang, lang)
                .one();
        HeWeather newWeather;
        long now = System.currentTimeMillis();
        if (oldWeather == null || now - oldWeather.getUpdateTime() > THREE_HOUR) {
            newWeather = WeatherUtil.getWeather(cid, lang);
        } else {
            String w = oldWeather.getRawData();
            return transTo(JSON.parseObject(w, HeWeather.class), city);
        }
        if (newWeather == null || newWeather.getHeWeather6() == null || newWeather.getHeWeather6().size() == 0) {
            return null;
        }

        WeatherVO weatherVO = transTo(newWeather, city);
        Weather weather = new Weather();
        weather.setCid(cid);
        weather.setCity(weatherVO.getCity());
        weather.setRawData(newWeather.toJson());
        weather.setCreateTime(now);
        weather.setUpdateTime(weatherVO.getUpdateTime());
        weather.setLang(lang);
        weatherMapper.replace(weather);
        return weatherVO;
    }

    @Override
    public WeatherVO getGFWeather(String city, String cid, String lon, String lat, String lang, String province, String country, String appCid) {
        if (StringUtils.isAnyBlank(lon, lat, lang)) {//经纬度,和lang是必要参数
            return null;
        }
        if (!"cn".equals(lang)) {
            lang = "en";
        }
        if (StringUtils.isBlank(cid)) {
            //通过app获取的cid
            if (StringUtils.isNotBlank(appCid)) {
                cid = weatherMapper.getGFCidByAppCid(appCid);
            }
            //通过国家,省,市 缓存查询
            if (StringUtils.isNotBlank(city) && StringUtils.isBlank(cid)) {
                cid = weatherMapper.getGFCidByCity(lang, city, province);
            }
            if (StringUtils.isEmpty(cid)) {//本地缓存没有cid
                GFWeather.Location cityData = gfWeatherUtil.getCityData(lon, lat, lang);
                if (cityData == null) {
                    return null;
                } else {
                    cid = cityData.getAreacode();
                    //当客户获取省市区不符合高分 省市区,将客户省市区保存
                    if (StringUtils.isNoneBlank(province, city)) {
                        try {
                            CityInfo cityInfo = new CityInfo();
                            cityInfo.setCid(cid);
                            if (StringUtils.isNotBlank(appCid)) {
                                cityInfo.setAppCid(appCid);
                            }
                            if (!"cn".equals(lang)) {
                                cityInfo.setCityEn(city);
                                cityInfo.setProvinceEn(province);
                            } else {
                                cityInfo.setCityCn(city);
                                cityInfo.setProvinceCn(province);
                            }
                            weatherMapper.insertCityData(cityInfo);
                            log.info("城市保存{},{}", city, province);
                        } catch (Exception e) {
                            log.error("insert cityinfo", e.getMessage());
                        }
                    } else {
                        city = cityData.getName();
                    }
                }
            }
        }
        Weather oldWeather = new LambdaQueryChainWrapper<>(weatherMapper)
                .eq(Weather::getCid, cid)
                .eq(Weather::getLang, lang)
                .one();
        GFWeather newWeather;
        long now = System.currentTimeMillis();
        if (oldWeather == null || now - oldWeather.getCreateTime() > THREE_HOUR) {
            Integer value = cacheService.getValue(CacheConfig.CacheEum.WEATHER_BLACKLIST.name(), cid);
            if (value != null) {
                return null;
            }
            newWeather = gfWeatherUtil.getWeather(cid, lang);
        } else {
            return transTo(JSON.parseObject(oldWeather.getRawData(), GFWeather.class), city, cid);
        }
        if (newWeather == null || newWeather.getWeatherInfoList() == null || newWeather.getWeatherInfoList().size() == 0) {
            cacheService.putValue(CacheConfig.CacheEum.WEATHER_BLACKLIST.name(), cid, 1);
            return null;
        }
        WeatherVO weatherVO = transTo(newWeather, city, cid);
        weatherVO.setCid(cid);
        Weather weather = new Weather();
        weather.setCid(cid);
        weather.setCity(weatherVO.getCity());
        weather.setRawData(newWeather.toJson());
        weather.setCreateTime(now);
        weather.setUpdateTime(weatherVO.getUpdateTime());
        weather.setLang(lang);
        weatherMapper.replace(weather);
        log.info("天气保存,{}", cid);
        return weatherVO;
    }

    private WeatherVO transTo(GFWeather weather, String city, String cid) {
        List<GFWeather.WeatherInfo> weatherInfoList = weather.getWeatherInfoList();
        if (weatherInfoList == null || weatherInfoList.size() == 0) {
            return null;
        }
        WeatherVO weatherVO = new WeatherVO();
        weatherVO.setCity(city);
        weatherVO.setCid(cid);
        GFWeather.WeatherInfo weatherInfo = weatherInfoList.get(0);
        weatherVO.setCondCode(weatherInfo.getCode_day());
        weatherVO.setCondTxt(weatherInfo.getText_day());
        weatherVO.setTmp(weatherInfo.getHigh());
        ArrayList<WeatherVO.WeatherDaily> dayList = new ArrayList<>();
        weatherInfoList.forEach(item -> {
            WeatherVO.WeatherDaily weatherDaily = new WeatherVO.WeatherDaily();
            weatherDaily.setDay(item.getDate());
            weatherDaily.setMax(item.getHigh());
            weatherDaily.setMin(item.getLow());
            weatherDaily.setDayCondCode(item.getCode_day());
            weatherDaily.setDayCondTxt(item.getText_day());
            weatherDaily.setNightCondCode(item.getCode_night());
            weatherDaily.setNightCondTxt(item.getText_night());
            weatherDaily.setPressure(item.getPressure());
            dayList.add(weatherDaily);
        });
        weatherVO.setDayList(dayList);
        Long timestamp = DateUtils.getTimestamp(DateUtils.dateFormat15, weather.getLast_update());
        weatherVO.setCreateTime(timestamp);
        weatherVO.setUpdateTime(timestamp);
        return weatherVO;
    }

    private WeatherVO transTo(HeWeather heWeather, String city) {
        HeWeather.HeWeather6Bean bean = heWeather.getHeWeather6().get(0);
        if (!"ok".equals(bean.getStatus())) {
            return null;
        }
        WeatherVO weatherVO = new WeatherVO();
        weatherVO.setCity(city);
        int size = bean.getDaily_forecast().size();
        if (null != bean.getNow()) {
            weatherVO.setCondCode(bean.getNow().getCond_code());
            weatherVO.setCondTxt(bean.getNow().getCond_txt());
            weatherVO.setTmp(bean.getNow().getTmp());
        } else {
            if (size > 0) {
                weatherVO.setCondCode(bean.getDaily_forecast().get(0).getCond_code_d());
                weatherVO.setCondTxt(bean.getDaily_forecast().get(0).getCond_txt_d());
                weatherVO.setTmp(bean.getDaily_forecast().get(0).getTmp_max());
            }
        }
        weatherVO.setCreateTime(System.currentTimeMillis());

        String u = bean.getUpdate().getLoc();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        long up = 0;
        try {
            up = sdf.parse(u).getTime();
        } catch (ParseException e) {
            return null;
        }
        weatherVO.setUpdateTime(up);
        List<WeatherVO.WeatherDaily> days = new ArrayList<>();

        for (int i = 0; i < size; i++) {
            WeatherVO.WeatherDaily daily = new WeatherVO.WeatherDaily();
            HeWeather.HeWeather6Bean.DailyForecastBean forecastBean = bean.getDaily_forecast().get(i);
            daily.setDay(forecastBean.getDate());
            daily.setDayCondCode(forecastBean.getCond_code_d());
            daily.setDayCondTxt(forecastBean.getCond_txt_d());
            daily.setNightCondCode(forecastBean.getCond_code_n());
            daily.setNightCondTxt(forecastBean.getCond_txt_n());
            daily.setMax(forecastBean.getTmp_max());
            daily.setMin(forecastBean.getTmp_min());
            days.add(daily);
        }
        weatherVO.setDayList(days);
        return weatherVO;
    }
}
